package xj.graph2d.app.project;

import java.awt.Dimension;

import java.util.List;
import java.util.ArrayList;

import java.awt.Component;
import java.awt.event.*;
import java.io.InputStream;
import java.util.LinkedList;
import java.util.List;

import javax.swing.*;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;

import org.jvnet.flamingo.bcb.*;
import org.jvnet.flamingo.common.StringValuePair;
import org.jvnet.flamingo.bcb.core.BreadcrumbTreeAdapterSelector;

import xj.graph2d.tree.ProjectPane;
import xj.graph2d.tree.ProjectTreeNode;

public class BreadcrumbAdapter 
  extends JBreadcrumbBar<Object> { 

  public BreadcrumbAdapter(ProjectPane projectPane) { 
    super(new TreeCallback(projectPane.getProjectTree()));
    this.projectPane = projectPane;
    this.tree = projectPane.getProjectTree();
    this.projectManager = projectPane.getProjectManager();
    this.callback = (TreeCallback) getCallback();
    this.treeAdapter = callback.getTreeAdapter();
    projectPane.setBreadcrumbAdapter(this);

    BreadcrumbPathListener listener = new BreadcrumbPathListener() { 
	public void breadcrumbPathEvent(BreadcrumbPathEvent event) {
	  //System.out.println("  BreadcrumbPath changed");
	  BreadcrumbBarModel<Object> model = getModel();
	  int n = model.getItemCount();
	  if (n > 0) { 
	    BreadcrumbItem<Object> lastItem = model.getItem(n - 1);
	    Object node = lastItem.getData();
	    //System.out.println("  BreadcrumbPath last item " + node.getClass().getName());
	    if (node instanceof ProjectTreeNode) { 
	      BreadcrumbAdapter.this.projectPane.selectProjectTreeNode((ProjectTreeNode) node);
	    }
	  }
	}
      };

    BreadcrumbBarModel<Object> model = getModel();
    model.addPathListener(listener);

    setPreferredSize(new Dimension(400, 20));
    setMinimumSize(new Dimension(400, 20));

    addHierarchyBoundsListener(new HierarchyBoundsAdapter() { 
	public void ancestorResized(HierarchyEvent e) {
	  Dimension dim = ((Component) e.getSource()).getParent().getSize();
	  BreadcrumbAdapter.this.setPreferredSize(new Dimension(dim.width - 150, 20));
	  BreadcrumbAdapter.this.setMinimumSize(new Dimension(dim.width - 150, 20));
	}
      });

    //System.out.println("BreadcrumbAdapter");
  }

  /**
   * Update the path of the breadcrumb bar based on the current tree path
   */
  public void updatePath() { 
    TreePath path = tree.getSelectionPath();
    if (path != null) { 
      Object[] nodes = path.getPath();
      if (nodes != null && nodes.length > 1) {
	// not showing the root
	int n = nodes.length;
	List<BreadcrumbItem<Object>> bcbPath = new ArrayList(n);
	for (int i = 1; i < n; i++) { 
	  Object node = nodes[i]; 
	  BreadcrumbItem<Object> item = new BreadcrumbItem<Object>(node.toString(), node);
	  //System.out.println("  BreadcrumbAdapter.updatePath() [" + i + "] " + node.toString());
	  item.setIcon(treeAdapter.getIcon(node));
	  bcbPath.add(item);
	}
	setPath(bcbPath); 
	validate();
      }
    }
  }

  protected JTree tree; 
  protected TreeCallback callback;
  protected TreeAdapter treeAdapter; 
  protected ProjectPane projectPane;
  protected ProjectManager projectManager;
  protected BreadcrumbBarModel<Object> model;

}

class TreeAdapter {

  JTree tree; 
 
  TreeAdapter(JTree tree) {
    this.tree = tree; 
  }

  private JLabel getRenderer(Object node) {
    Component renderer = 
      tree.getCellRenderer().getTreeCellRendererComponent(tree, node, false, false,
							  tree.getModel().isLeaf(node), 0, false);
    if (renderer instanceof JLabel)
      return (JLabel) renderer;
    return null;
  }
  
  public String toString(Object node) {
    JLabel label = getRenderer(node);
    if (label != null)
      return label.getText();
    return null;
  }
  
  public Icon getIcon(Object node) {
    JLabel label = getRenderer(node);
    if (label != null)
      return label.getIcon();
    return null;
  }

}

class TreeCallback extends BreadcrumbBarCallBack<Object> {
    
  protected TreeModel treeModel;

  protected TreeAdapter treeAdapter;
  
  protected boolean isRootVisible;

  public TreeCallback(JTree tree) { 
    this(tree.getModel(), new TreeAdapter(tree), false);
  }
  
  public TreeCallback(TreeModel treeModel, 
		      TreeAdapter treeAdapter,
		      boolean isRootVisible) {
    this.treeModel = treeModel;
    this.treeAdapter = treeAdapter;
    this.isRootVisible = isRootVisible;
  }

  public TreeAdapter getTreeAdapter() {  
    return treeAdapter;
  } 
 
  @Override
  public List<StringValuePair<Object>> getPathChoices(List<BreadcrumbItem<Object>> path) {
    if (path == null) {
      Object root = this.treeModel.getRoot();
      List<StringValuePair<Object>> bRoots = new LinkedList<StringValuePair<Object>>();
      if (isRootVisible) {
	StringValuePair<Object> rootPair = 
	  new StringValuePair<Object>(this.treeAdapter.toString(root), root);
	rootPair.set("icon", this.treeAdapter.getIcon(root));
	bRoots.add(rootPair);
      } else {
	for (int i = 0; i < this.treeModel.getChildCount(root); i++) {
	  Object rootChild = this.treeModel.getChild(root, i);
	  StringValuePair<Object> rootPair = 
	    new StringValuePair<Object>(this.treeAdapter.toString(rootChild), rootChild);
	  rootPair.set("icon", this.treeAdapter.getIcon(rootChild));
	  bRoots.add(rootPair);
	}
      }
      return bRoots;
    }
    if (path.size() == 0)
      return null;
    
    Object lastInPath = path.get(path.size() - 1).getData();
    
    if (this.treeModel.isLeaf(lastInPath))
      return null;
    LinkedList<StringValuePair<Object>> lResult = new LinkedList<StringValuePair<Object>>();
    for (int i = 0; i < this.treeModel.getChildCount(lastInPath); i++) {
      Object child = this.treeModel.getChild(lastInPath, i);
      //if (this.treeModel.isLeaf(child))
      //continue;
      StringValuePair<Object> pair = 
	new StringValuePair<Object>(this.treeAdapter.toString(child), child);
      pair.set("icon", this.treeAdapter.getIcon(child));
      lResult.add(pair);
    }
    return lResult;
  }

  @Override
  public List<StringValuePair<Object>> getLeafs(List<BreadcrumbItem<Object>> path) {
    Object lastInPath = path.get(path.size() - 1).getData();
    if (this.treeModel.isLeaf(lastInPath))
      return null;
    LinkedList<StringValuePair<Object>> lResult = new LinkedList<StringValuePair<Object>>();
    for (int i = 0; i < this.treeModel.getChildCount(lastInPath); i++) {
      Object child = this.treeModel.getChild(lastInPath, i);
      if (!this.treeModel.isLeaf(child))
	continue;
      StringValuePair<Object> pair = 
	new StringValuePair<Object>(this.treeAdapter.toString(child), child);
      pair.set("icon", this.treeAdapter.getIcon(child));
      lResult.add(pair);
    }
    return lResult;
  }

  @Override
  public InputStream getLeafContent(Object leaf) {
    return null;
  }

}

 

